package org.jslaughter.component.physics.motion;

import org.nvframe.component.AbstractComponent;
import org.nvframe.component.physics.state.PhysicsPosition;
import org.nvframe.entity.Entity;
import org.nvframe.event.EventService;
import org.nvframe.event.eventtype.UpdateEvent;
import org.nvframe.event.eventtype.UpdateListener;
import org.nvframe.exception.NVFrameException;
import org.nvframe.manager.EntityManager;
import org.nvframe.util.Settings;

/**
 * 
 * @author Nik Van Looy
 */
public class FollowMotion extends AbstractComponent implements UpdateListener {

	private float stepSpeed;
	private float rotSpeed;
	private Entity targetEntity;

	public FollowMotion(String id, Entity owner, Settings settings) throws NVFrameException {
		super(id, owner);
		
		stepSpeed = settings.getFloat("stepSpeed");
		rotSpeed = settings.getFloat("rotSpeed");
		
		targetEntity = EntityManager.getInstance().getEntity("ent_player");
		
		if(targetEntity == null)
			throw new NVFrameException("cant find targetEntity");
		
		EventService.getInstance().addEventListener(this);
	}

	public float getStepSpeed() {
		return stepSpeed;
	}
	
	/**
	 * 
	 * 
	 * @param currentDir
	 * @param destDir
	 * @param delta
	 * @return
	 */
	private float calculateDirection(float currentDir, float destDir, int delta) {
		boolean clockwise = true;

		currentDir = currentDir % 360 < 0 ? 360 - Math.abs(currentDir % 360) : Math.abs(currentDir % 360);
		destDir = destDir % 360 < 0 ? 360 - Math.abs(destDir % 360) : Math.abs(destDir % 360);
		
		if(Math.abs(currentDir - destDir) <= rotSpeed)
			return currentDir;
		
		clockwise = destDir - currentDir < 0 ? false : true;
		
		if(Math.abs(destDir - currentDir) > 180)
			clockwise = !clockwise;
		
		if(clockwise)
			return currentDir + rotSpeed * delta;
		else
			return currentDir - rotSpeed * delta;
	}

	@Override
	public void onUpdate(UpdateEvent event) {
		int delta = event.getDelta();
		
		PhysicsPosition position = (PhysicsPosition) owner.getComponent(PhysicsPosition.class);
		PhysicsPosition targetPosition = (PhysicsPosition) targetEntity.getComponent(PhysicsPosition.class);
		
		if(position == null || targetPosition == null)
			return;
		
		float toTargetDirection = (float) Math.toDegrees(Math.atan2(targetPosition.getY() - position.getY(), 
				targetPosition.getX() - position.getX()));
		
		// set velocity so owner moves to targetEntity's position
		position.adjustVelocity(0, 0);
		position.adjustVelocity((float) (Math.cos(Math.toRadians(toTargetDirection)) * stepSpeed * delta), 
				(float) (Math.sin(Math.toRadians(toTargetDirection)) * stepSpeed * delta));
		
		// change direction of owner's render
		position.setDirection(calculateDirection(position.getDirection(), toTargetDirection, delta));
		
	}
	
	@Override
	public void removed() {
		EventService.getInstance().removeEventListener(this);
	}
}